<?php
namespace jiosen\sijiu;

use think\Db;

class DiscuzCode {

	function absoluteurl($url) {
		global $_G;
		if($url{0} == '/') {
			return 'http://'.$_SERVER['HTTP_HOST'].$url;
		} else {
			return $_G['siteurl'].$url;
		}
	}

	function atag($aoptions, $text) {
		$href = $this->getoptionvalue('href', $aoptions);

		if(substr($href, 0, 7) == 'mailto:') {
			$tag = 'email';
			$href = substr($href, 7);
		} else {
			$tag = 'url';
			if(!preg_match("/^[a-z0-9]+:/i", $href)) {
				$href = $this->absoluteurl($href);
			}
		}

		return "[$tag=$href]".trim($this->recursion('a', $text, 'atag'))."[/$tag]";
	}

	function divtag($divoptions, $text) {
		$prepend = $append = '';

		$this->parsestyle($divoptions, $prepend, $append);
		$align = $this->getoptionvalue('align', $divoptions);

		switch($align) {
			case 'left':
			case 'center':
			case 'right':
				break;
			default:
				$align = '';
		}

		if($align) {
			$prepend .= "[align=$align]";
			$append .= "[/align]";
		}
		$append .= "\n";

		return $prepend.$this->recursion('div', $text, 'divtag').$append;
	}

	function fetchoptionvalue($option, $text) {
		if(($position = strpos($text, $option)) !== false) {
			$delimiter = $position + strlen($option);
			if($text{$delimiter} == '"') {
				$delimchar = '"';
			} elseif($text{$delimiter} == '\'') {
				$delimchar = '\'';
			} else {
				$delimchar = ' ';
			}
			$delimloc = strpos($text, $delimchar, $delimiter + 1);
			if($delimloc === false) {
				$delimloc = strlen($text);
			} elseif($delimchar == '"' OR $delimchar == '\'') {
				$delimiter++;
			}
			return trim(substr($text, $delimiter, $delimloc - $delimiter));
		} else {
			return '';
		}
	}

	function fonttag($fontoptions, $text) {
		$tags = array('font' => 'face=', 'size' => 'size=', 'color' => 'color=');
		$prependtags = $appendtags = '';

		foreach($tags as $bbcode => $locate) {
			$optionvalue = fetchoptionvalue($locate, $fontoptions);
			if($optionvalue) {
				$prependtags .= "[$bbcode=$optionvalue]";
				$appendtags = "[/$bbcode]$appendtags";
			}
		}

		$this->parsestyle($fontoptions, $prependtags, $appendtags);

		return $prependtags.$this->recursion('font', $text, 'fonttag').$appendtags;
	}

	function getoptionvalue($option, $text) {
		preg_match("/$option(\s+?)?\=(\s+?)?[\"']?(.+?)([\"']|$|>)/is", $text, $matches);
		return isset($matches[3]) ? trim($matches[3]) : '';
	}

	function html2bbcode($text) {
		$text = strip_tags($text, '<table><tr><td><b><strong><i><em><u><a><div><span><p><strike><blockquote><ol><ul><li><font><img><br><br/><h1><h2><h3><h4><h5><h6><script>');

		if($this->ismozilla()) {
			$text = preg_replace("/(?<!<br>|<br \/>|\r)(\r\n|\n|\r)/", ' ', $text);
		}

		$pregfind = array(
			"/<script.*>.*<\/script>/siU",
			'/on(mousewheel|mouseover|click|load|onload|submit|focus|blur)="[^"]*"/i',
			"/(\r\n|\n|\r)/",
			"/<table([^>]*(width|background|background-color|bgcolor)[^>]*)>/siUe",
			"/<table.*>/siU",
			"/<tr.*>/siU",
			"/<td>/i",
			"/<td(.+)>/siUe",
			"/<\/td>/i",
			"/<\/tr>/i",
			"/<\/table>/i",
			'/<h([0-9]+)[^>]*>/siUe',
			'/<\/h([0-9]+)>/siU',
			"/<img[^>]+smilieid=\"(\d+)\".*>/esiU",
			"/<img([^>]*src[^>]*)>/eiU",
			"/<a\s+?name=.+?\".\">(.+?)<\/a>/is",
			"/<br.*>/siU",
			"/<span\s+?style=\"float:\s+(left|right);\">(.+?)<\/span>/is",
		);
		$pregreplace = array(
			'',
			'',
			'',
			"tabletag('\\1')",
			'[table]',
			'[tr]',
			'[td]',
			"tdtag('\\1')",
			'[/td]',
			'[/tr]',
			'[/table]',
			"\"[size=\".(7 - \\1).\"]\"",
			"[/size]\n\n",
			"smileycode('\\1')",
			"imgtag('\\1')",
			'\1',
			"\n",
			"[float=\\1]\\2[/float]",
		);
		$text = preg_replace($pregfind, $pregreplace, $text);

		$text = $this->recursion('b', $text, 'simpletag', 'b');
		$text = $this->recursion('strong', $text, 'simpletag', 'b');
		$text = $this->recursion('i', $text, 'simpletag', 'i');
		$text = $this->recursion('em', $text, 'simpletag', 'i');
		$text = $this->recursion('u', $text, 'simpletag', 'u');
		$text = $this->recursion('a', $text, 'atag');
		$text = $this->recursion('font', $text, 'fonttag');
		$text = $this->recursion('blockquote', $text, 'simpletag', 'indent');
		$text = $this->recursion('ol', $text, 'listtag');
		$text = $this->recursion('ul', $text, 'listtag');
		$text = $this->recursion('div', $text, 'divtag');
		$text = $this->recursion('span', $text, 'spantag');
		$text = $this->recursion('p', $text, 'ptag');

		$pregfind = array("/(?<!\r|\n|^)\[(\/list|list|\*)\]/", "/<li>(.*)((?=<li>)|<\/li>)/iU", "/<p.*>/iU", "/<p><\/p>/i", "/(<a>|<\/a>|<\/li>)/is", "/<\/?(A|LI|FONT|DIV|SPAN)>/siU", "/\[url[^\]]*\]\[\/url\]/i", "/\[url=javascript:[^\]]*\](.+?)\[\/url\]/is");
		$pregreplace = array("\n[\\1]", "\\1\n", "\n", '', '', '', '', "\\1");
		$text = preg_replace($pregfind, $pregreplace, $text);

		$strfind = array('&nbsp;', '&lt;', '&gt;', '&amp;');
		$strreplace = array(' ', '<', '>', '&');
		$text = str_replace($strfind, $strreplace, $text);

		return dhtmlspecialchars(trim($text));
	}

	function imgtag($attributes) {
		$value = array('src' => '', 'width' => '', 'height' => '');
		preg_match_all("/(src|width|height)=([\"|\']?)([^\"']+)(\\2)/is", dstripslashes($attributes), $matches);
		if(is_array($matches[1])) {
			foreach($matches[1] as $key => $attribute) {
				$value[strtolower($attribute)] = $matches[3][$key];
			}
		}
		@extract($value);
		if(!preg_match("/^http:\/\//i", $src)) {
			$src = absoluteurl($src);
		}
		return $src ? ($width && $height ? '[img='.$width.','.$height.']'.$src.'[/img]' : '[img]'.$src.'[/img]') : '';
	}

	function ismozilla() {
		$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
		if(strpos($useragent, 'gecko') !== FALSE) {
			preg_match("/gecko\/(\d+)/", $useragent, $regs);
			return $regs[1];
		}
		return FALSE;
	}

	function litag($listoptions, $text) {
		return '[*]'.rtrim($text);
	}

	function listtag($listoptions, $text, $tagname) {
		require_once libfile('function/post');
		$text = preg_replace('/<li>((.(?!<\/li))*)(?=<\/?ol|<\/?ul|<li|\[list|\[\/list)/siU', '<li>\\1</li>', $text).(isopera() ? '</li>' : NULL);
		$text = $this->recursion('li', $text, 'litag');

		if($tagname == 'ol') {
			$listtype = fetchoptionvalue('type=', $listoptions) ? fetchoptionvalue('type=', $listoptions) : 1;
			if(in_array($listtype, array('1', 'a', 'A'))) {
				$opentag = '[list='.$listtype.']';
			}
		} else {
			$opentag = '[list]';
		}
		return $text ? $opentag.$this->recursion($tagname, $text, 'listtag').'[/list]' : FALSE;
	}

	function parsestyle($tagoptions, &$prependtags, &$appendtags) {
		$searchlist = array(
			array('tag' => 'align', 'option' => TRUE, 'regex' => 'text-align:\s*(left);?', 'match' => 1),
			array('tag' => 'align', 'option' => TRUE, 'regex' => 'text-align:\s*(center);?', 'match' => 1),
			array('tag' => 'align', 'option' => TRUE, 'regex' => 'text-align:\s*(right);?', 'match' => 1),
			array('tag' => 'color', 'option' => TRUE, 'regex' => '(?<![a-z0-9-])color:\s*([^;]+);?', 'match' => 1),
			array('tag' => 'font', 'option' => TRUE, 'regex' => 'font-family:\s*([^;]+);?', 'match' => 1),
			array('tag' => 'size', 'option' => TRUE, 'regex' => 'font-size:\s*(\d+(\.\d+)?(px|pt|in|cm|mm|pc|em|ex|%|));?', 'match' => 1),
			array('tag' => 'b', 'option' => FALSE, 'regex' => 'font-weight:\s*(bold);?'),
			array('tag' => 'i', 'option' => FALSE, 'regex' => 'font-style:\s*(italic);?'),
			array('tag' => 'u', 'option' => FALSE, 'regex' => 'text-decoration:\s*(underline);?')
		);

		$style = $this->getoptionvalue('style', $tagoptions);
		$style = preg_replace(
			"/(?<![a-z0-9-])color:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)(;?)/ie",
			'sprintf("color: #%02X%02X%02X$4", $1, $2, $3)',
			$style
		);
		foreach($searchlist as $searchtag) {
			if(preg_match('/'.$searchtag['regex'].'/i', $style, $match)) {
				$opnvalue = $match["$searchtag[match]"];
				$prependtags .= '['.$searchtag['tag'].($searchtag['option'] == TRUE ? '='.$opnvalue.']' : ']');
				$appendtags = '[/'.$searchtag['tag']."]$appendtags";
			}
		}
	}

	function ptag($poptions, $text) {
		$align = $this->getoptionvalue('align', $poptions);

		switch($align) {
			case 'left':
			case 'center':
			case 'right':
				break;
			default:
				$align = '';
		}

		$prepend = $append = '';
		parsestyle($poptions, $prepend, $append);
		if($align) {
			$prepend .= "[align=$align]";
			$append .= "[/align]";
		}
		$append .= "\n";

		return $prepend.$this->recursion('p', $text, 'ptag').$append;
	}

	function recursion($tagname, $text, $function, $extraargs = '') {
		$tagname = strtolower($tagname);
		$open_tag = "<$tagname";
		$open_tag_len = strlen($open_tag);
		$close_tag = "</$tagname>";
		$close_tag_len = strlen($close_tag);

		$beginsearchpos = 0;
		do {
			$textlower = strtolower($text);
			$tagbegin = @strpos($textlower, $open_tag, $beginsearchpos);
			if($tagbegin === FALSE) {
				break;
			}

			$strlen = strlen($text);

			$inquote = '';
			$found = FALSE;
			$tagnameend = FALSE;
			for($optionend = $tagbegin; $optionend <= $strlen; $optionend++) {
				$char = $text{$optionend};
				if(($char == '"' || $char == "'") && $inquote == '') {
					$inquote = $char;
				} elseif(($char == '"' || $char == "'") && $inquote == $char) {
					$inquote = '';
				} elseif($char == '>' && !$inquote) {
					$found = TRUE;
					break;
				} elseif(($char == '=' || $char == ' ') && !$tagnameend) {
					$tagnameend = $optionend;
				}
			}
			if(!$found) {
				break;
			}
			if(!$tagnameend) {
				$tagnameend = $optionend;
			}
			$offset = $optionend - ($tagbegin + $open_tag_len);
			$tagoptions = substr($text, $tagbegin + $open_tag_len, $offset);
			$acttagname = substr($textlower, $tagbegin + 1, $tagnameend - $tagbegin - 1);
			if($acttagname != $tagname) {
				$beginsearchpos = $optionend;
				continue;
			}

			$tagend = strpos($textlower, $close_tag, $optionend);
			if($tagend === FALSE) {
				break;
			}

			$nestedopenpos = strpos($textlower, $open_tag, $optionend);
			while($nestedopenpos !== FALSE && $tagend !== FALSE) {
				if($nestedopenpos > $tagend) {
					break;
				}
				$tagend = strpos($textlower, $close_tag, $tagend + $close_tag_len);
				$nestedopenpos = strpos($textlower, $open_tag, $nestedopenpos + $open_tag_len);
			}
			if($tagend === FALSE) {
				$beginsearchpos = $optionend;
				continue;
			}

			$localbegin = $optionend + 1;
			$localtext = $this->$function($tagoptions, substr($text, $localbegin, $tagend - $localbegin), $tagname, $extraargs);

			$text = substr_replace($text, $localtext, $tagbegin, $tagend + $close_tag_len - $tagbegin);

			$beginsearchpos = $tagbegin + strlen($localtext);
		} while($tagbegin !== FALSE);

		return $text;
	}

	function simpletag($options, $text, $tagname, $parseto) {
		if(trim($text) == '') {
			return '';
		}
		$text = $this->recursion($tagname, $text, 'simpletag', $parseto);
		return "[$parseto]{$text}[/$parseto]";
	}

	function smileycode($smileyid) {
		global $_G;

		if(!is_array($_G['cache']['smileycodes'])) {
			loadcache(array('bbcodes_display', 'bbcodes', 'smileycodes', 'smilies', 'smileytypes', 'domainwhitelist'));
		}
		foreach($_G['cache']['smileycodes'] as $id => $code) {
			if($smileyid == $id) {
				return $code;
			}
		}
	}

	function spantag($spanoptions, $text) {
		$prependtags = $appendtags = '';
		parsestyle($spanoptions, $prependtags, $appendtags);

		return $prependtags.$this->recursion('span', $text, 'spantag').$appendtags;
	}

	function tabletag($attributes) {
		$attributes = dstripslashes($attributes);
		$width = '';
		if(preg_match("/width=([\"|\']?)(\d{1,4}%?)(\\1)/is", $attributes, $matches)) {
			$width = substr($matches[2], -1) == '%' ? (substr($matches[2], 0, -1) <= 98 ? $matches[2] : '98%') : ($matches[2] <= 560 ? $matches[2] : '560');
		} elseif(preg_match("/width\s?:\s?(\d{1,4})([px|%])/is", $attributes, $matches)) {
			$width = $matches[2] == '%' ? ($matches[1] <= 98 ? $matches[1].'%' : '98%') : ($matches[1] <= 560 ? $matches[1] : '560');
		}
		if(preg_match("/(?:background|background-color|bgcolor)[:=]\s*([\"']?)((rgb\(\d{1,3}%?,\s*\d{1,3}%?,\s*\d{1,3}%?\))|(#[0-9a-fA-F]{3,6})|([a-zA-Z]{1,20}))(\\1)/i", $attributes, $matches)) {
			$bgcolor = $matches[2];
			$width = $width ? $width : '98%';
		} else {
			$bgcolor = '';
		}
		return $bgcolor ? "[table=$width,$bgcolor]" :($width ? "[table=$width]" : '[table]');
	}

	function tdtag($attributes) {
		$value = array('colspan' => 1, 'rowspan' => 1, 'width' => '');
		preg_match_all("/(colspan|rowspan|width)=([\"|\']?)(\d{1,4}%?)(\\2)/is", dstripslashes($attributes), $matches);
		if(is_array($matches[1])) {
			foreach($matches[1] as $key => $attribute) {
				$value[strtolower($attribute)] = $matches[3][$key];
			}
		}
		@extract($value);
		return $width == '' ? ($colspan == 1 && $rowspan == 1 ? '[td]' : "[td=$colspan,$rowspan]") : "[td=$colspan,$rowspan,$width]";
	}
	function get_censor_data()
	{
		$data = cache('bbs_censor_data');
		if(empty($data)){
			$data = Db::name('common_syscache')->where(array('cname'=>'censor'))->value('data');
			if($data){
				$data = unserialize($data);
				cache('bbs_censor_data',$data,600);
			}
		}
		return $data;
	}
	function get_bbcodes_display()
	{
		$data = cache('bbs_bbcodes_display');
		if(empty($data)){
			$data = Db::name('common_syscache')->where(array('cname'=>'bbcodes_display'))->value('data');
			if($data){
				$data = unserialize($data);
				cache('bbs_bbcodes_display',$data,864000);
			}
		}
		return $data;
	}
	function censor_check($message)
	{
		$limitnum = 500;
		$bbcodes_display = $this->get_bbcodes_display();
		$censor_words = $this->get_censor_data();
		$bbcodes = 'b|i|color|size|font|align|list|indent|email|hide|quote|code|free|table|tr|td|img|swf|attach|payto|float'.($bbcodes_display ? '|'.implode('|', array_keys($bbcodes_display)) : '');
		if(is_array($censor_words['banned']) && !empty($censor_words['banned'])) {
			foreach($censor_words['banned'] as $banned_words) {
				if(preg_match_all($banned_words, @preg_replace(array("/\[($bbcodes)=?.*\]/iU", "/\[\/($bbcodes)\]/i"), '', $message), $matches)) {
					return array('status'=>0,'msg'=>'抱歉，您填写的内容包含不良信息而无法提交');
				}
			}
		}
		if(is_array($censor_words['mod']) && !empty($censor_words['mod'])) {
			// if($modword !== NULL) {
			$message = preg_replace($censor_words['mod'], $modword, $message);
			// }
			foreach($censor_words['mod'] as $mod_words) {
				if(preg_match_all($mod_words, @preg_replace(array("/\[($bbcodes)=?.*\]/iU", "/\[\/($bbcodes)\]/i"), '', $message), $matches)) {
					return array('status'=>0,'msg'=>'抱歉，您填写的内容包含不良信息而无法提交');
				}
			}
		}
		if(!empty($censor_words['filter'])) {
			$i = 0;
			while($find_words = array_slice($censor_words['filter']['find'], $i, $limitnum)) {
				if(empty($find_words)) break;
				$replace_words = array_slice($censor_words['filter']['replace'], $i, $limitnum);
				$i += $limitnum;
				$message = preg_replace($find_words, $replace_words, $message);
			}
		}

		return array('status'=>1,'message'=>$message);
	}
}



?>